/*
 * @Author: hzm 
 * @Date: 2020-06-20 21:50:20 
 * @Last Modified by: hzm
 * @Last Modified time: 2020-06-20 22:32:41
 */

#include "PipeEvent.h"
#include <sys/socket.h>
#include "MLogManager.h"
#include "event2/util.h"
#include "event.h"

using namespace HeyIM;


PipeEvent::PipeEvent(event_base* base, VoidParamHandler handler): Event(base, handler) {
    memset(m_pipe, 0, sizeof(m_pipe[0]) * 2);
    init();
}

PipeEvent::~PipeEvent() {
    MLogInfo("PipeEvent is free");
}

void PipeEvent::init() {
    MLogInfo("PipeEvent::init {}","");

    int ret = evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, m_pipe);
    if(ret < 0) {
        int err = EVUTIL_SOCKET_ERROR();
        MLogError("PipeEvent::init error, create socketpair failed {}", err);
        destroy();
        return;
    }

    if(!m_base) {
        MLogError("PipeEvent::init failed, base is nullptr {}", __LINE__);
        destroy();
        return;
    }

    if(m_event) {
        MLogError("PipeEvent::init failed, event not free {}", __LINE__);
        event_del(m_event);
        event_free(m_event);
        m_event = nullptr;
        destroy();
        return;
    }
    
    m_event = event_new(m_base, m_pipe[1], EV_READ | EV_PERSIST, &PipeEvent::pipeHandleCallback, this);

    MLogInfo("PipeEvent::init sucessfully");
}

void PipeEvent::post() {
    MLogInfo("PipeEvent::post");

    char buf[1] = {0};
    
    int ret = ::send(m_pipe[0], buf, sizeof(buf), 0);
    if(ret < 0) {
        MLogError("PipeEvent::post send error:{}", ret);
    }

}

void PipeEvent::destroy() {
    if(m_pipe[0] > 0) {
        EVUTIL_CLOSESOCKET(m_pipe[0]);
        EVUTIL_CLOSESOCKET(m_pipe[1]);
        memset(m_pipe, 0, sizeof(m_pipe[0]) * 2);

        MLogInfo("PipeEvent::destroy");
    }
}

void PipeEvent::pipeHandleCallback(int fd, short flag, void* arg) {

    PipeEvent* p = (PipeEvent*)arg;
    char buf[1024];
    int ret = ::recv(p->m_pipe[1], buf, sizeof(buf), 0);
    MLogInfo("PipeEvent::pipeHandleCallback fd:{}, flag:{}, ret", fd, flag, ret);
    if(ret > 0) {
        p->m_handler();
    }


}